//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include "ChannelPackage.h"

unsigned int ChannelPackage::g_SentPackageCount = 0;

unsigned int ChannelPackage::g_ReceivedPackageCount = 0;

void ChannelPackage::WriteInteger(char* buffer, int number)
{
    *buffer = (char) ((number & 0xff000000) >> 24);
    *(buffer + 1) = (char) ((number & 0xff0000) >> 16);
    *(buffer + 2) = (char) ((number & 0xff00) >> 8);
    *(buffer + 3) = (char) (number & 0xff);
}

int ChannelPackage::ReadInteger(ReadInputStream is, int* number)
{
    char buffer[4];
    int ret = 0;
    int recv = 0;
    int received = 0;

    do {
        ret = is(buffer + received, 4 - received, &recv);
        if (0 != ret) {
            // reading from physical layer failed.
            return ret;
        }
        received += recv;
    } while (received < 4);

    *number = (buffer[0] << 24 & 0xff000000)
            | (buffer[1] << 16 & 0xff0000)
            | (buffer[2] << 8 & 0xff00)
            | (buffer[3] & 0xff);
    return 0;
}

int ChannelPackage::ReadInteger(char* buffer)
{
    return (buffer[0] << 24 & 0xff000000)
            | (buffer[1] << 16 & 0xff0000)
            | (buffer[2] << 8 & 0xff00)
            | (buffer[3] & 0xff);
}

int ChannelPackage::CRCCheck(void* data, unsigned int size)
{
    unsigned int crc = 0;
    unsigned char *ptr = (unsigned char *)data;
    unsigned char i;
    while (size--) {
        for (i = 0x80; i != 0; i >>= 1) {
            if ((crc&0x80000000) != 0) {
                crc<<=1;
                crc^=0x04C11DB7;
            }
            else
                crc<<=1;

            if((*ptr&i) != 0) crc ^= 0x04C11DB7;
        }
        ptr++;
    }
    return (int) crc;
}

unsigned int ChannelPackage::NextPackageNumber()
{
    ChannelPackage::g_SentPackageCount++;
    return ChannelPackage::g_SentPackageCount;
}

int ChannelPackage::Write(WriteOutputStream os)
{
    int size = GetPackageSize();
    char* buffer = new char[size];
    if (buffer == NULL) {
        return CHANNEL_OUT_OF_MEMORY; // out of memory
    }
    WriteBuffer(buffer);
    int sent = 0;
    int ret = 0;
    do {
        int written = 0;
        ret = os((void *) (buffer + sent), size - sent, &written);
        if (0 != ret) {
            delete[] buffer;
            return CHANNEL_IO_ERROR; // io error
        }
        sent += written;
    } while (sent != size);
    delete[] buffer;
    return CHANNEL_OK; // write ok
}
